home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_2 / ispell-3.3ljr / ispell / ispell.c < prev    next >
C/C++ Source or Header  |  1992-10-08  |  36KB  |  1,814 lines

  1. /*
  2.  * ispell.c - An interactive spelling corrector.
  3.  *
  4.  * Copyright (c), 1983, by Pace Willisson
  5.  * Permission for non-profit use is hereby granted.
  6.  * All other rights reserved.
  7.  *
  8.  * 1987, Robert McQueer, added:
  9.  *    -w option & handling of extra legal word characters
  10.  *    -d option for alternate dictionary file
  11.  *    -p option & WORDLIST variable for alternate personal dictionary
  12.  *    -x option to suppress .bak files.
  13.  *    8 bit text & config.h parameters
  14.  * 1987, Geoff Kuenning, added:
  15.  *    -c option for creating suffix suggestions from raw words
  16.  *    suffixes in personal dictionary file
  17.  *    hashed personal dictionary file
  18.  *    -S option for unsorted word lists
  19.  * 1987, Greg Schaffer, added:
  20.  *    -T option (for TeX and LaTeX instead of troff) [later changed to -t]
  21.  *       passes over \ till next whitespace.
  22.  *       does not recognize % (comment)
  23.  * 1989, Tomas Rokicki, added:
  24.  *      ispell'local'words to indicate rest of line for local words
  25.  *      -L option to write local words when done
  26.  *      fixed `sleep' so some error messages could be seen.
  27.  * 1989, Loren J. Rittle, added:
  28.  *    Fixed ISpell to use proper STDOUT/STDIN streams when used in
  29.  *       non-interactive modes.
  30.  *    ARexx Server Mode, invoke with -r option ( for rexx )
  31.  *    Thanks to Tomas Rokicki for MinRexx! and example code.
  32.  * 1990, Loren J. Rittle, reworked:
  33.  *    Converted to SAS/C v5.10.
  34.  *    Added full prototype checking.
  35.  *    Fixed more bugs, many memory related.
  36.  *    Finally left UNIX behind completely.
  37.  *    Got rid of alot of (what I would call) kludge code, left
  38.  *       over from the original port job.  See amiga.c for more details.
  39.  * 1991, Loren J. Rittle, added:
  40.  *    many new ARexx Server Mode commands.
  41.  *    released to the world.
  42.  * 1992, W.G.J. Langeveld, added:
  43.  *    -R switch, same as -r, but prints out line numbers and column numbers
  44.  *    during "filecheck".
  45.  * 1992, Loren J. Rittle, reworked:
  46.  *    Converted to SAS/C v6.0.
  47.  *    Reworked W.G.J. Langeveld's '-R' switch to make new ARexx interface
  48.  *    point instead of startup time option.  Once again, '-r' is the only
  49.  *    server mode provided by ispell.
  50.  */
  51.  
  52. #undef _STRICT_ANSI
  53. #include <stdio.h>
  54. #define _STRICT_ANSI
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. extern int  creat  (char *, int);
  59. #pragma msg 148 ignore push
  60. #pragma msg 149 ignore push
  61. #pragma msg 61 ignore push
  62. #include <dos/dos.h>
  63. #pragma msg 149 pop
  64. #pragma msg 61 pop
  65. #include "config.h"
  66. #include "ispell.h"
  67. #include "version.h"
  68.  
  69. struct rexxCommandList rcl[] =
  70. {
  71.   {"add", &rexxadd},
  72.   {"quickadd", &rexxquickadd},
  73.   {"check", &rexxcheck},
  74.   {"quickcheck", &rexxquickcheck},
  75.   {"lookup", &rexxlookup},
  76.   {"filecheck", &rexxfilecheck},
  77.   {"extendedfilecheck", &rexxextendedfilecheck},
  78.   {"version", &rexxversion},
  79.   {"exit", &rexxexit},
  80.   {NULL, NULL}
  81. };
  82.  
  83. SHORT KeepGoing = TRUE;    /* main loop control value */
  84.  
  85. char rootword[BUFSIZ];
  86. struct dent *lastdent;
  87.  
  88. char *hashstrings;
  89. struct hashheader hashheader;
  90.  
  91. char tempfile[200];
  92.  
  93. #define ISTEXTERM(c)   (((c) == '{') || \
  94.             ((c) == '}') || \
  95.             ((c) == '[') || \
  96.             ((c) == ']'))
  97.  
  98. int li, co;    /* lines, columns */
  99.  
  100. FILE *infile;
  101. FILE *outfile;
  102.  
  103. char hashname[MAXPATHLEN];
  104.  
  105. /*
  106. ** we use extended character set range specifically to allow intl.
  107. ** character set characters.  We are being REALLY paranoid about indexing
  108. ** this array - explicitly cast into unsigned INTEGER, then mask
  109. ** If NO8BIT is set, text will be masked to ascii range.
  110. */
  111.      static int Trynum;
  112. #ifdef NO8BIT
  113.      static char Try[128];
  114.      static char Checkch[128];
  115. #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
  116. #else
  117.      static char Try[256];
  118.      static char Checkch[256];
  119. #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
  120. #endif
  121.  
  122.      static int sortit = 1;
  123.  
  124. void givehelp (void)
  125. {
  126.   erase ();
  127.   printcon (Version_ID);
  128.   printcon ("\n");
  129.   printcon ("Whenever a word is found that is not in the dictionary,\n");
  130.   printcon ("it is printed on the first line of the screen.  If the dictionary\n");
  131.   printcon ("contains any similar words, they are listed with a single digit\n");
  132.   printcon ("next to each one.  You have the option of replacing the word\n");
  133.   printcon ("completely, or choosing one of the suggested words.\n");
  134.   printcon ("\n");
  135.   printcon ("Commands are:\n\n");
  136.   printcon ("R       Replace the misspelled word completely.\n");
  137.   printcon ("Space   Accept the word this time only\n");
  138.   printcon ("A       Accept the word for the rest of this file.\n");
  139.   printcon ("I       Accept the word, and put it in your private dictionary.\n");
  140.   printcon ("0-9     Replace with one of the suggested words.\n");
  141.   printcon ("L       Look up words via regular expression.\n");
  142.   printcon ("Q       Write the rest of this file, ignoring misspellings, ");
  143.   printcon ("and start next file.\n");
  144.   printcon ("X       Exit immediately.  Asks for confirmation.  ");
  145.   printcon ("Leaves file unchanged.\n");
  146.   printcon ("^L      Redraw screen.\n");
  147.   printcon ("\n\n");
  148.   printcon ("-- Type space to continue --");
  149.   while (getccon () != ' ')
  150.     ;
  151. }
  152.  
  153. int cflag = 0;
  154. int lflag = 0;
  155. int incfileflag = 0;
  156. int aflag = 0;
  157. int fflag = 0;
  158. int sflag = 0;
  159. int xflag = 0;
  160. int tflag = 0;
  161. int llflag = 0;
  162. int rflag = 0;
  163. /*
  164. *   Willy's flag: for more extended spell-file capability
  165. */
  166. int wflag = 0;
  167.  
  168. #define MAXPOSSIBLE    100    /* Max no. of possibilities to generate */
  169.  
  170. char possibilities[MAXPOSSIBLE][BUFSIZ];
  171. int pcount;
  172. int maxposslen;
  173.  
  174. char *askfilename;
  175.  
  176. static char *Cmd;
  177.  
  178. void usage (void)
  179. {
  180.   fprintf (stderr,
  181.     "Usage: %s [-dfile | -pfile | -wchars | -t | -x | -S] file .....\n",
  182.        Cmd);
  183.   fprintf (stderr,
  184.        "       %s -r\n",
  185.        Cmd);
  186.   fprintf (stderr,
  187.        "       %s [-dfile | -pfile | -wchars] -l\n",
  188.        Cmd);
  189.   fprintf (stderr,
  190.        "       %s [-dfile | -pfile | -ffile | -s] {-a | -A}\n",
  191.        Cmd);
  192.   fprintf (stderr, "       %s [-wchars] -c\n", Cmd);
  193.   fprintf (stderr, "       %s -v\n", Cmd);
  194.   exit (1);
  195. }
  196.  
  197. static void initckch (void)
  198. {
  199.   register int c;
  200.  
  201.   Trynum = 0;
  202. #ifdef NO8BIT
  203.   for (c = 0; c < 128; ++c)
  204.     {
  205. #else
  206.   for (c = 0; c < 256; ++c)
  207.     {
  208. #endif
  209.       if (myalpha ((char) c))
  210.     {
  211.       Checkch[c] = (char) 1;
  212.       if (myupper ((char) c))
  213.         {
  214.           Try[Trynum] = (char) c;
  215.           ++Trynum;
  216.         }
  217.     }
  218.       else
  219.     Checkch[c] = (char) 0;
  220.     }
  221. }
  222.  
  223. void main (int argc, char **argv)
  224. {
  225.   char *p;
  226.   char *cpd;
  227.   char num[4];
  228.   unsigned mask;
  229.   static char outbuf[BUFSIZ];
  230.  
  231.   Cmd = *argv;
  232.  
  233.   initckch ();
  234.   sprintf (hashname, "%s%s", LIBDIR, DEFHASH);
  235.  
  236.   cpd = NULL;
  237.  
  238.   argv++;
  239.   argc--;
  240.   while (argc && **argv == '-')
  241.     {
  242.       switch ((*argv)[1])
  243.     {
  244.     case 'r':
  245.       rflag++;
  246.       lflag++;
  247.       break;
  248.     case 'v':
  249.       printf ("%s\n", Version_ID);
  250.       exit (0);
  251.     case 't':
  252.       tflag++;
  253.       break;
  254.     case 'A':
  255.       incfileflag = 1;
  256.       aflag = 1;
  257.       break;
  258.     case 'a':
  259.       aflag++;
  260.       break;
  261.     case 'c':
  262.       cflag++;
  263.       lflag++;
  264.       break;
  265.     case 'x':
  266.       xflag++;
  267.       break;
  268.     case 'f':
  269.       fflag++;
  270.       p = (*argv) + 2;
  271.       if (*p == '\0')
  272.         {
  273.           argv++;
  274.           argc--;
  275.           if (argc == 0)
  276.         usage ();
  277.           p = *argv;
  278.         }
  279.       askfilename = p;
  280.       break;
  281.     case 'l':
  282.       lflag++;
  283.       break;
  284.     case 'L':
  285.       llflag++;
  286.       break;
  287.     case 's':
  288.       sflag++;
  289.       break;
  290.     case 'S':
  291.       sortit = 0;
  292.       break;
  293.     case 'p':
  294.       cpd = (*argv) + 2;
  295.       if (*cpd == '\0')
  296.         {
  297.           argv++;
  298.           argc--;
  299.           if (argc == 0)
  300.         usage ();
  301.           cpd = *argv;
  302.         }
  303.       break;
  304.     case 'd':
  305.       p = (*argv) + 2;
  306.       if (*p == '\0')
  307.         {
  308.           argv++;
  309.           argc--;
  310.           if (argc == 0)
  311.         usage ();
  312.           p = *argv;
  313.         }
  314.       if (*p == '/')
  315.         strcpy (hashname, p);
  316.       else
  317.         sprintf (hashname, "%s%s", LIBDIR, p);
  318.       break;
  319.     case 'w':
  320.       num[3] = '\0';
  321. #ifdef NO8BIT
  322.       mask = 0x7f;
  323. #else
  324.       mask = 0xff;
  325. #endif
  326.       p = (*argv) + 2;
  327.       if (*p == '\0')
  328.         {
  329.           argv++;
  330.           argc--;
  331.           if (argc == 0)
  332.         usage ();
  333.           p = *argv;
  334.         }
  335.       while (Trynum <= mask && *p != '\0')
  336.         {
  337.           if (*p != 'n' && *p != '\\')
  338.         {
  339.           Checkch[((unsigned) (*p)) & mask] = (char) 1;
  340.           Try[Trynum] = *p & mask;
  341.           ++p;
  342.         }
  343.           else
  344.         {
  345.           ++p;
  346.           num[0] = '\0';
  347.           num[1] = '\0';
  348.           num[2] = '\0';
  349.           num[3] = '\0';
  350.           if (isdigit (p[0]))
  351.             num[0] = p[0];
  352.           if (isdigit (p[1]))
  353.             num[1] = p[1];
  354.           if (isdigit (p[2]))
  355.             num[2] = p[2];
  356.           if (p[-1] == 'n')
  357.             {
  358.               p += strlen (num);
  359.               num[0] = atoi (num);
  360.             }
  361.           else
  362.             {
  363.               p += strlen (num);
  364.               if (num[0])
  365.             num[0] -= '0';
  366.               if (num[1])
  367.             {
  368.               num[0] <<= 3;
  369.               num[0] += num[1] - '0';
  370.             }
  371.               if (num[2])
  372.             {
  373.               num[0] <<= 3;
  374.               num[0] += num[2] - '0';
  375.             }
  376.             }
  377.           Try[Trynum] = num[0] & mask;
  378.           Checkch[num[0] & mask] = 1;
  379.         }
  380.           ++Trynum;
  381.         }
  382.       break;
  383.     default:
  384.       usage ();
  385.     }
  386.       argv++;
  387.       argc--;
  388.     }
  389.  
  390.   if (!argc && !lflag && !aflag && !rflag)
  391.     usage ();
  392.  
  393.   if (linit () < 0)
  394.     exit (0);
  395.  
  396.   treeinit (cpd);
  397.  
  398.   if (rflag)
  399.     {
  400.       servermode ();
  401.       exit (0);
  402.     }
  403.  
  404.   if (aflag)
  405.     {
  406.       askmode ();
  407.       exit (0);
  408.     }
  409.  
  410.   setbuf (stdout, outbuf);
  411.   if (lflag)
  412.     {
  413.       infile = stdin;
  414.       checkfile ();
  415.       exit (0);
  416.     }
  417.  
  418.   terminit ();
  419.  
  420.   while (argc--)
  421.     dofile (*argv++);
  422.  
  423.   done ();
  424. }
  425.  
  426. char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
  427. char *currentchar;
  428. char token[BUFSIZ];
  429.  
  430. int quit;
  431.  
  432. char *currentfile = NULL;
  433.  
  434. void dofile (char *filename)
  435. {
  436.   int c;
  437.   char bakfile[256];
  438.   char *cp;
  439.  
  440.   currentfile = filename;
  441.  
  442.   if ((infile = fopen (filename, "r")) == NULL)
  443.     {
  444.       fprintf (stderr, "Can't open %s\n", filename);
  445.       sleep (2);
  446.       return;
  447.     }
  448.  
  449.   if (access (filename, 2) < 0)
  450.     {
  451.       fprintf (stderr, "Can't write to %s\n", filename);
  452.       sleep (2);
  453.       return;
  454.     }
  455.  
  456.   tmpnam (tempfile);
  457.   if ((outfile = fopen (tempfile, "w")) == NULL)
  458.     {
  459.       fprintf (stderr, "Can't create %s\n", tempfile);
  460.       sleep (2);
  461.       return;
  462.     }
  463.  
  464.   quit = 0;
  465.  
  466.   /* See if the file is a .tex file.  If so, set the appropriate flag. */
  467.   if ((cp = strrchr (filename, '.')) != NULL && strcmp (cp, ".tex") == 0)
  468.     tflag = 1;
  469.   checkfile ();
  470.  
  471.   fclose (infile);
  472.   fclose (outfile);
  473.  
  474.   if (!cflag)
  475.     treeoutput ();
  476.  
  477.   if ((infile = fopen (tempfile, "r")) == NULL)
  478.     {
  479.       fprintf (stderr, "temporary file disappeared (%s)\n", tempfile);
  480.       sleep (2);
  481.       return;
  482.     }
  483.  
  484.   sprintf (bakfile, "%s%s", filename, BAKEXT);
  485.   remove (bakfile);
  486.   if (rename (filename, bakfile))
  487.     {
  488.       fprintf (stderr, "can't rename %s to %s\n", filename, bakfile);
  489.       sleep (2);
  490.       return;
  491.     }
  492.  
  493.   /* if we can't write new, preserve .bak regardless of xflag */
  494.   if ((outfile = fopen (filename, "w")) == NULL)
  495.     {
  496.       fprintf (stderr, "can't create %s\n", filename);
  497.       sleep (2);
  498.       return;
  499.     }
  500.  
  501.   while ((c = getc (infile)) != EOF)
  502.     putc (c, outfile);
  503.  
  504.   fclose (infile);
  505.   fclose (outfile);
  506.  
  507.   remove (tempfile);
  508.   if (xflag)
  509.     remove (bakfile);
  510. }
  511.  
  512. struct RexxMsg *RexxMsg;
  513.  
  514. void checkfile (void)
  515. {
  516.   register char *p;
  517.   register int len;
  518.   int addflag;
  519.   int count = 0;
  520.  
  521. /*
  522. *   Willy's mod: keep track of line number
  523. */
  524.   long linenum = 0;
  525.  
  526.   secondbuf[0] = 0;
  527.  
  528.   while (1)
  529.     {
  530.       strcpy (firstbuf, secondbuf);
  531.       if (quit)
  532.     {            /* quit can't be set in l mode */
  533.       while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
  534.         fputs (secondbuf, outfile);
  535.       break;
  536.     }
  537.  
  538.       if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
  539.     break;
  540. /*
  541. *   Willy's mod: keep track of line number
  542. */
  543.       linenum++;
  544.  
  545.       currentchar = secondbuf;
  546.       addflag = 0;
  547.       len = strlen (secondbuf) - 1;
  548.  
  549.       if (!tflag)
  550.     {
  551.       /* skip over .if */
  552.       if (strncmp (currentchar, ".if t", 5) == 0
  553.           || strncmp (currentchar, ".if n", 5) == 0)
  554.         {
  555.           copyout (¤tchar, 5);
  556.           while (*currentchar && isspace (*currentchar))
  557.         copyout (¤tchar, 1);
  558.         }
  559.  
  560.       /* skip over .ds XX or .nr XX */
  561.       if (strncmp (currentchar, ".ds ", 4) == 0
  562.           || strncmp (currentchar, ".de ", 4) == 0
  563.           || strncmp (currentchar, ".nr ", 4) == 0)
  564.         {
  565.           copyout (¤tchar, 3);
  566.           while (*currentchar && isspace (*currentchar))
  567.         copyout (¤tchar, 1);
  568.           while (*currentchar && !isspace (*currentchar))
  569.         copyout (¤tchar, 1);
  570.           if (*currentchar == 0)
  571.         {
  572.           if (!lflag)
  573.             putc ('\n', outfile);
  574.           continue;
  575.         }
  576.         }
  577.     }
  578.  
  579.       if (secondbuf[len] == '\n')
  580.     secondbuf[len] = 0;
  581.  
  582.       /* if this is a formatter command, skip over it */
  583.       if (!tflag && *currentchar == '.')
  584.     {
  585.       while (*currentchar && !myspace (*currentchar))
  586.         {
  587.           if (!lflag)
  588.         putc (*currentchar, outfile);
  589.           currentchar++;
  590.         }
  591.       if (*currentchar == 0)
  592.         {
  593.           if (!lflag)
  594.         putc ('\n', outfile);
  595.           continue;
  596.         }
  597.     }
  598.  
  599.       while (1)
  600.     {
  601.       while (*currentchar && !iswordch (*currentchar))
  602.         {
  603.           if (tflag)    /* TeX or LaTeX stuff */
  604.         {
  605.           if (*currentchar == '\\')
  606.             {
  607.               /* skip till whitespace */
  608.               while (*currentchar &&
  609.                  (!isspace (*currentchar) &&
  610.                   !ISTEXTERM (*currentchar)))
  611.             {
  612.               if (!lflag)
  613.                 putc (*currentchar, outfile);
  614.               currentchar++;
  615.             }
  616.               continue;
  617.             }
  618.         }
  619.           else
  620.         {
  621.           /* formatting escape sequences */
  622.           if (*currentchar == '\\')
  623.             {
  624.               switch (currentchar[1])
  625.             {
  626.             case 'f':
  627.               if (currentchar[2] != '(')
  628.                 {
  629.                   /* font change: \fX */
  630.                   copyout (¤tchar, 3);
  631.                 }
  632.               else
  633.                 {
  634.                   /* font change: \f(XY */
  635.                   copyout (¤tchar, 5);
  636.                 }
  637.               continue;
  638.             case 's':
  639.               /* size change */
  640.               p = currentchar + 2;
  641.               if (*p == '+' || *p == '-')
  642.                 p++;
  643.               /* This looks wierd 'cause we assume
  644.               ** *p is now a digit.
  645.               */
  646.               if (isdigit (p[1]))
  647.                 p++;
  648.               copyout (¤tchar,
  649.                    p - currentchar + 1);
  650.               continue;
  651.             case '(':
  652.               /* extended char set escape: \(XX */
  653.               copyout (¤tchar, 4);
  654.               continue;
  655.             case '*':
  656.               if (currentchar[2] != '(')
  657.                 copyout (¤tchar, 3);
  658.               else
  659.                 copyout (¤tchar, 5);
  660.               continue;
  661.             default:
  662.               break;
  663.             }
  664.             }
  665.         }
  666.  
  667.           if (!lflag)
  668.         putc (*currentchar, outfile);
  669.           currentchar++;
  670.         }
  671.  
  672.       if (*currentchar == 0)
  673.         break;
  674.  
  675.       p = token;
  676.       while (iswordch (*currentchar) ||
  677.          (*currentchar == '\'' &&
  678.           iswordch (*(currentchar + 1))))
  679.         *p++ = *currentchar++;
  680.       *p = 0;
  681. /*
  682.  *   mods by tom rokicki to handle local document words automagically
  683.  */
  684.       if (token[0] == 'i' &&
  685.           strcmp (token, "ispell'local'words") == 0)
  686.         {
  687.           addflag = 1;
  688.         }
  689.       else
  690.         {
  691.           if (addflag)
  692.         {
  693.           if (!good (token))
  694.             {
  695.               treeinsert (token, 0);
  696.             }
  697.         }
  698.           if (lflag)
  699.         {
  700.           if (!good (token) && !cflag)
  701.             if (rflag) {
  702. /*
  703. *   Willy's mod: if wflag, print out word, line number and colum
  704. */
  705.               if (wflag) {
  706.             static char var[64];
  707.             static char value[64];
  708.             
  709.             sprintf (value, "%d", ++count);
  710.             SetRexxVar (RexxMsg, "ISPELLRESULT.COUNT", value, strlen (value));
  711.  
  712.             sprintf (var,"ISPELLRESULT.%d.WORD", count);
  713.             SetRexxVar (RexxMsg, var, token, strlen (token));
  714.  
  715.             sprintf (value, "%d", linenum);
  716.             sprintf (var,"ISPELLRESULT.%d.LINE", count);
  717.             SetRexxVar (RexxMsg, var, value, strlen (value));
  718.  
  719.             sprintf (value, "%d", currentchar - secondbuf - strlen(token) + 1);
  720.             sprintf (var,"ISPELLRESULT.%d.COLUMN", count);
  721.             SetRexxVar (RexxMsg, var, value, strlen (value));
  722.                       }
  723.                       else {
  724.                  fprintf (outfile, "%s\n", token);
  725.                       }
  726.                     }
  727.             else
  728.               fprintf (stdout, "%s\n", token);
  729.         }
  730.           else
  731.         {
  732.           if (!quit)
  733.             correct (token, ¤tchar);
  734.         }
  735.         }
  736.       if (!lflag)
  737.         fprintf (outfile, "%s", token);
  738.     }
  739.       if (!lflag)
  740.     putc ('\n', outfile);
  741.     }
  742.   if (llflag)
  743.     {
  744.       lldump ();
  745.     }
  746. }
  747.  
  748. void correct (char *token, char **currentchar)
  749. {
  750.   register int c;
  751.   register int i;
  752.   int col_ht;
  753.   int ncols;
  754.   char *start_l2;
  755.   char *begintoken;
  756.  
  757.   begintoken = *currentchar - strlen (token);
  758.  
  759. checkagain:
  760.   if (good (token))
  761.     return;
  762.  
  763.   erase ();
  764.   printcon ("    %s", token);
  765.   if (currentfile)
  766.     printcon ("              File: %s", currentfile);
  767.   printcon ("\n\n");
  768.  
  769.   makepossibilities (token);
  770.  
  771.   /*
  772.    * Make sure we have enough room on the screen to hold the
  773.    * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
  774.    * is the maximum number of columns that will fit.
  775.    */
  776.   col_ht = li - 6;        /* Height of columns of words */
  777.   ncols = co / (maxposslen + 8);
  778.   if (pcount > ncols * col_ht)
  779.     pcount = ncols * col_ht;
  780.  
  781. #ifdef EQUAL_COLUMNS
  782.   /*
  783.    * Equalize the column sizes.  The last column will be short.
  784.    */
  785.   col_ht = (pcount + ncols - 1) / ncols;
  786. #endif
  787.  
  788.   for (i = 0; i < pcount; i++)
  789.     {
  790.       move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  791.       printcon ("%2d: %s", i, possibilities[i]);
  792.     }
  793.  
  794.   move (li - 3, 0);
  795.   show_line (firstbuf, firstbuf, 0);
  796.  
  797.   start_l2 = secondbuf;
  798.   if (line_size (secondbuf, *currentchar) > co - 1)
  799.     {
  800.       start_l2 = begintoken - (co / 2);
  801.       while (start_l2 < begintoken)
  802.     {
  803.       i = line_size (start_l2, *currentchar) + 1;
  804.       if (i <= co)
  805.         break;
  806.       start_l2 += i - co;
  807.     }
  808.       if (start_l2 > begintoken)
  809.     start_l2 = begintoken;
  810.       if (start_l2 < secondbuf)
  811.     start_l2 = secondbuf;
  812.     }
  813.   show_line (start_l2, begintoken, strlen (token));
  814.  
  815.   while (1)
  816.     {
  817.       switch (c = (getccon () & NOPARITY))
  818.     {
  819.     case 'Z' & 037:
  820.       stop ();
  821.       erase ();
  822.       goto checkagain;
  823.     case ' ':
  824.       erase ();
  825.       return;
  826.     case 'x':
  827.     case 'X':
  828.       printcon ("Are you sure you want to throw away your changes? ");
  829.       c = (getccon () & NOPARITY);
  830.       if (c == 'y' || c == 'Y')
  831.         {
  832.           erase ();
  833.           done ();
  834.         }
  835.       putchar (7);
  836.       goto checkagain;
  837.     case 'i':
  838.     case 'I':
  839.       treeinsert (token, 1);
  840.       erase ();
  841.       return;
  842.     case 'a':
  843.     case 'A':
  844.       treeinsert (token, 0);
  845.       if (llflag)
  846.         llinsert (token);
  847.       erase ();
  848.       return;
  849.     case 'L' & 037:
  850.       goto checkagain;
  851.     case '?':
  852.       givehelp ();
  853.       goto checkagain;
  854.     case 'r':
  855.     case 'R':
  856.       move (li - 1, 0);
  857.       printcon ("Replace with: ");
  858.       if (getline (token) == NULL)
  859.         {
  860.           putccon (7);
  861.           erase ();
  862.           goto checkagain;
  863.         }
  864.       inserttoken (secondbuf, begintoken, token, currentchar);
  865.       erase ();
  866.       goto checkagain;
  867.     case '0':
  868.     case '1':
  869.     case '2':
  870.     case '3':
  871.     case '4':
  872.     case '5':
  873.     case '6':
  874.     case '7':
  875.     case '8':
  876.     case '9':
  877.       i = c - '0';
  878.       if (pcount > 10
  879.           && i > 0 && i <= (pcount - 1) / 10)
  880.         {
  881.           c = getccon () & NOPARITY;
  882.           if (c >= '0' && c <= '9')
  883.         i = i * 10 + c - '0';
  884.           else if (c != '\n')
  885.         {
  886.           putccon (7);
  887.           break;
  888.         }
  889.         }
  890.       if (i < pcount)
  891.         {
  892.           strcpy (token, possibilities[i]);
  893.           inserttoken (secondbuf, begintoken,
  894.                token, currentchar);
  895.           erase ();
  896.           return;
  897.         }
  898.       putccon (7);
  899.       break;
  900.     case '\r':        /* This makes typing \n after single digits */
  901.     case '\n':        /* ..less obnoxious */
  902.       break;
  903.     case 'l':
  904.     case 'L':
  905.       {
  906.         char buf[100];
  907.         move (li - 1, 0);
  908.         printcon ("Lookup string ('*' is wildcard): ");
  909.         if (getline (buf) == NULL)
  910.           {
  911.         putccon (7);
  912.         erase ();
  913.         goto checkagain;
  914.           }
  915.         printcon ("\n\n");
  916.         lookharder (buf);
  917.         erase ();
  918.         goto checkagain;
  919.       }
  920.     case 'q':
  921.     case 'Q':
  922.       quit = 1;
  923.       erase ();
  924.       return;
  925.     default:
  926.       putccon (7);
  927.       break;
  928.     }
  929.     }
  930. }
  931.  
  932. void show_line (char *line, char *invstart, int invlen)
  933. {
  934.   register int width;
  935.  
  936.   width = 0;
  937.   while (line != invstart && width < co - 1)
  938.     width += show_char (*line++, width);
  939.   if (invlen)
  940.     {
  941.       inverse ();
  942.       while (--invlen >= 0 && width < co - 1)
  943.     width += show_char (*line++, width);
  944.       normal ();
  945.     }
  946.   while (*line && width < co - 1)
  947.     width += show_char (*line++, width);
  948.   printcon ("\n");
  949. }
  950.  
  951. int show_char (int ch, int linew)
  952. {
  953.   if (ch == '\t')
  954.     {
  955.       putccon ('\t');
  956.       return 8 - (linew & 0x07);
  957.     }
  958.   else if (ch < ' ')
  959.     {
  960.       putccon ('^');
  961.       putccon (ch + 'A' - '\001');
  962.       return 2;
  963.     }
  964.   putccon (ch);
  965.   return 1;
  966. }
  967.  
  968. int line_size (char *buf, char *bufend)
  969. {
  970.   register int width;
  971.  
  972.   for (width = 0; buf < bufend && *buf; buf++)
  973.     {
  974.       if (*buf == '\t')
  975.     width = (width + 8) & ~0x07;
  976.       else if (*buf < ' ')
  977.     width += 2;
  978.       else
  979.     width++;
  980.     }
  981.   return width;
  982. }
  983.  
  984. void inserttoken (char *buf, char *start, char *token, char **currentchar)
  985. {
  986.   char copy[BUFSIZ];
  987.   register char *p, *q;
  988.  
  989.   strcpy (copy, buf);
  990.  
  991.   for (p = buf, q = copy; p != start; p++, q++)
  992.     *p = *q;
  993.   q += *currentchar - start;
  994.   while (*token && iswordch (*token))
  995.     *p++ = *token++;
  996.   *currentchar = p;
  997.   if (*token)
  998.     {
  999.  
  1000.       /*
  1001.       ** The token changed to two words.  Split it up and save the
  1002.       ** second one for later.
  1003.       */
  1004.  
  1005.       *p++ = *token;
  1006.       *token++ = '\0';
  1007.       while (*token)
  1008.     *p++ = *token++;
  1009.     }
  1010.   while (*p++ = *q++)
  1011.     ;
  1012. }
  1013.  
  1014. int casecmp (char *a, char *b)
  1015. {
  1016.   register char *ap;
  1017.   register char *bp;
  1018.  
  1019.   for (ap = a, bp = b; *ap; ap++, bp++)
  1020.     {
  1021.       if (mylower (*ap))
  1022.     {
  1023.       if (mylower (*bp))
  1024.         {
  1025.           if (*ap != *bp)
  1026.         return *ap - *bp;
  1027.         }
  1028.       else
  1029.         {
  1030.           if (toupper (*ap) != *bp)
  1031.         return toupper (*ap) - *bp;
  1032.         }
  1033.     }
  1034.       else
  1035.     {
  1036.       if (myupper (*bp))
  1037.         {
  1038.           if (*ap != *bp)
  1039.         return *ap - *bp;
  1040.         }
  1041.       else
  1042.         {
  1043.           if (tolower (*ap) != *bp)
  1044.         return tolower (*ap) - *bp;
  1045.         }
  1046.     }
  1047.     }
  1048.   if (*bp != '\0')
  1049.     return -((int)*bp);
  1050.   return strcmp (a, b);
  1051. }
  1052.  
  1053. void makepossibilities (char *word)
  1054. {
  1055.   register int i;
  1056.  
  1057.   for (i = 0; i < MAXPOSSIBLE; i++)
  1058.     possibilities[i][0] = 0;
  1059.   pcount = 0;
  1060.   maxposslen = 0;
  1061.  
  1062. #ifdef CAPITALIZE
  1063.   wrongcapital (word);
  1064. #endif
  1065.   if (pcount < MAXPOSSIBLE)
  1066.     wrongletter (word);
  1067.   if (pcount < MAXPOSSIBLE)
  1068.     extraletter (word);
  1069.   if (pcount < MAXPOSSIBLE)
  1070.     missingletter (word);
  1071.   if (pcount < MAXPOSSIBLE)
  1072.     transposedletter (word);
  1073.  
  1074.   if (sortit && pcount)
  1075.     qsort ((char *) possibilities, pcount,
  1076.        sizeof (possibilities[0]), casecmp);
  1077. }
  1078.  
  1079. int insert (char *word)
  1080. {
  1081.   register int i;
  1082.  
  1083.   for (i = 0; i < pcount; i++)
  1084.     if (strcmp (possibilities[i], word) == 0)
  1085.       return (0);
  1086.  
  1087.   strcpy (possibilities[pcount++], word);
  1088.   i = strlen (word);
  1089.   if (i > maxposslen)
  1090.     maxposslen = i;
  1091.   if (pcount >= MAXPOSSIBLE)
  1092.     return (-1);
  1093.   else
  1094.     return (0);
  1095. }
  1096.  
  1097. #ifdef CAPITALIZE
  1098. int wrongcapital (char *word)
  1099. {
  1100.   char newword[BUFSIZ];
  1101.  
  1102.   /*
  1103.   ** All-uppercase is always legal.  If the word matches, "ins_cap"
  1104.   ** will recapitalize it correctly.
  1105.   */
  1106.   strcpy (newword, word);
  1107.   upcase (newword);
  1108.   if (good (newword))
  1109.     return ins_cap (newword, word);
  1110.   return 0;
  1111. }
  1112.  
  1113. #endif
  1114.  
  1115. void wrongletter (char *word)
  1116. {
  1117.   register int i, j, c, n;
  1118.   char newword[BUFSIZ];
  1119.  
  1120.   n = strlen (word);
  1121.   strcpy (newword, word);
  1122. #ifdef CAPITALIZE
  1123.   upcase (newword);
  1124. #endif
  1125.  
  1126.   for (i = 0; i < n; i++)
  1127.     {
  1128.       for (j = 0; j < Trynum; ++j)
  1129.     {
  1130.       newword[i] = Try[j];
  1131.       if (good (newword))
  1132.         {
  1133.           if (ins_cap (newword, word) < 0)
  1134.         return;
  1135.         }
  1136.     }
  1137. #ifdef CAPITALIZE
  1138.       c = word[i];
  1139.       if (islower (c))
  1140.     newword[i] = toupper (c);
  1141.       else
  1142.     newword[i] = c;
  1143. #else
  1144.       newword[i] = word[i];
  1145. #endif
  1146.     }
  1147. }
  1148.  
  1149. void extraletter (char *word)
  1150. {
  1151.   char newword[BUFSIZ];
  1152.   register char *p, *s, *t;
  1153.  
  1154.   if (strlen (word) < 3)
  1155.     return;
  1156.  
  1157.   for (p = word; *p; p++)
  1158.     {
  1159.       for (s = word, t = newword; *s; s++)
  1160.     if (s != p)
  1161.       *t++ = *s;
  1162.       *t = 0;
  1163. #ifdef CAPITALIZE
  1164.       if (good (upcase (newword)))
  1165.     {
  1166.       if (ins_cap (newword, word) < 0)
  1167.         return;
  1168.     }
  1169. #else
  1170.       if (good (newword))
  1171.     {
  1172.       if (ins_cap (newword, word) < 0)
  1173.         return;
  1174.     }
  1175. #endif
  1176.     }
  1177. }
  1178.  
  1179. void missingletter (char *word)
  1180. {
  1181.   char newword[BUFSIZ];
  1182.   register char *p, *r, *s, *t;
  1183.   register int i;
  1184.  
  1185.   for (p = word; p == word || p[-1]; p++)
  1186.     {
  1187.       for (s = newword, t = word; t != p; s++, t++)
  1188.     *s = *t;
  1189.       r = s++;
  1190.       while (*t)
  1191.     *s++ = *t++;
  1192.       *s = 0;
  1193.       for (i = 0; i < Trynum; ++i)
  1194.     {
  1195.       *r = Try[i];
  1196. #ifdef CAPITALIZE
  1197.       if (good (upcase (newword)))
  1198.         {
  1199.           if (ins_cap (newword, word) < 0)
  1200.         return;
  1201.         }
  1202. #else
  1203.       if (good (newword))
  1204.         {
  1205.           if (ins_cap (newword, word) < 0)
  1206.         return;
  1207.         }
  1208. #endif
  1209.     }
  1210.     }
  1211. }
  1212.  
  1213. void transposedletter (char *word)
  1214. {
  1215.   char newword[BUFSIZ];
  1216.   register int t;
  1217.   register char *p;
  1218.  
  1219.   strcpy (newword, word);
  1220.   for (p = newword; p[1]; p++)
  1221.     {
  1222.       t = p[0];
  1223.       p[0] = p[1];
  1224.       p[1] = t;
  1225. #ifdef CAPITALIZE
  1226.       if (good (upcase (newword)))
  1227.     {
  1228.       if (ins_cap (newword, word) < 0)
  1229.         return;
  1230.     }
  1231. #else
  1232.       if (good (newword))
  1233.     {
  1234.       if (ins_cap (newword, word) < 0)
  1235.         return;
  1236.     }
  1237. #endif
  1238.       t = p[0];
  1239.       p[0] = p[1];
  1240.       p[1] = t;
  1241.     }
  1242. }
  1243.  
  1244. /* Insert one or more correctly capitalized versions of pattern */
  1245. int ins_cap (char *word, char *pattern)
  1246. {
  1247.   static char newword[BUFSIZ];
  1248.   register char *p;
  1249.   char *psave;
  1250.   register int wcount;
  1251.  
  1252.   if (*word == 0)
  1253.     return 0;
  1254.  
  1255.   strcpy (newword, word);
  1256. #ifdef CAPITALIZE
  1257.   if (lastdent->allcaps)
  1258.     return insert (upcase (newword));    /* Uppercase required */
  1259.   for (p = pattern; *p; p++)
  1260.     if (mylower (*p))
  1261.       break;
  1262.   if (*p == '\0')
  1263.     return insert (upcase (newword));    /* Pattern was all caps */
  1264.   for (p = pattern; *p; p++)
  1265.     if (myupper (*p))
  1266.       break;
  1267.   if (*p == '\0')
  1268.     {                /* Pattern was all lower */
  1269.       if (!lastdent->followcase && !lastdent->capitalize)
  1270.     return insert (lowcase (newword));
  1271.       /*
  1272.       ** If there's a followcase version that's all-lower,
  1273.       ** insert only that version.
  1274.       */
  1275.       if (lastdent->followcase)
  1276.     {
  1277.       p = lastdent->word;
  1278.       p += strlen (p) + 1;
  1279.       wcount = (*p++ & 0xFF);
  1280.       while (--wcount >= 0)
  1281.         {
  1282.           for (psave = ++p;
  1283.            *p && !myupper (*p);
  1284.            p++)
  1285.         ;
  1286.           if (*p == '\0')    /* Was it all lowercase? */
  1287.         return insert (psave);    /* Yup, quit */
  1288.           while (*p++)
  1289.         ;        /* Skip to next case sample */
  1290.         }
  1291.     }
  1292.     }
  1293.   /*
  1294.   ** The sample wasn't all-upper, and either it wasn't all-lower or
  1295.   ** all-lower is illegal.  Insert all legal capitalizations.  In
  1296.   ** some cases, this may include all-lowercase.
  1297.   */
  1298.   if (lastdent->capitalize)
  1299.     {
  1300.       lowcase (newword);
  1301.       if (mylower (newword[0]))
  1302.     newword[0] = toupper (newword[0]);
  1303.       insert (newword);
  1304.     }
  1305.   if (lastdent->followcase)
  1306.     {
  1307.       p = lastdent->word;
  1308.       p += strlen (p) + 1;
  1309.       wcount = (*p++ & 0xFF);
  1310.       while (--wcount >= 0)
  1311.     {
  1312.       /* Insert every variation;  it's easier */
  1313.       if (insert (++p) < 0)
  1314.         return -1;
  1315.       while (*p++)
  1316.         ;            /* Skip to end of sample */
  1317.     }
  1318.       return 0;
  1319.     }
  1320.   if (lastdent->capitalize)
  1321.     return 0;
  1322.   /*
  1323.   ** We get here only if none of the special capitalization flags are
  1324.   ** set.  If first letter of the pattern is capitalized, capitalize
  1325.   ** the first letter of the result.  Otherwise produce all lowercase.
  1326.   */
  1327.   lowcase (newword);
  1328.   if (myupper (pattern[0]) && mylower (newword[0]))
  1329.     newword[0] = toupper (newword[0]);
  1330.   return insert (newword);
  1331. #else
  1332.   if (myupper (pattern[0]))
  1333.     {
  1334.       if (myupper (pattern[1]))
  1335.     {
  1336.       for (p = word, q = newword; *p; p++, q++)
  1337.         {
  1338.           if (mylower (*p))
  1339.         *q = toupper (*p);
  1340.           else
  1341.         *q = *p;
  1342.         }
  1343.       *q = 0;
  1344.     }
  1345.       else
  1346.     {
  1347.       if (mylower (word[0]))
  1348.         newword[0] = toupper (word[0]);
  1349.       else
  1350.         newword[0] = word[0];
  1351.  
  1352.       for (p = word + 1, q = newword + 1; *p; p++, q++)
  1353.         if (myupper (*p))
  1354.           *q = tolower (*p);
  1355.         else
  1356.           *q = *p;
  1357.  
  1358.       *q = 0;
  1359.     }
  1360.     }
  1361.   else
  1362.     {
  1363.       for (p = word, q = newword; *p; p++, q++)
  1364.     if (myupper (*p))
  1365.       *q = tolower (*p);
  1366.     else
  1367.       *q = *p;
  1368.       *q = 0;
  1369.     }
  1370.   return insert (newword);
  1371. #endif
  1372. }
  1373.  
  1374. char *getline (char *s)
  1375. {
  1376.   register char *p;
  1377.   register int c;
  1378.  
  1379.   p = s;
  1380.  
  1381.   while (1)
  1382.     {
  1383.       c = (getccon () & NOPARITY);
  1384.       if (c == '\\')
  1385.     {
  1386.       putccon ('\\');
  1387.       c = (getccon () & NOPARITY);
  1388.       backup ();
  1389.       putccon (c);
  1390.       *p++ = c;
  1391.     }
  1392.       else if (c == ('G' & 037))
  1393.     {
  1394.       return (NULL);
  1395.     }
  1396.       else if ((c == '\n') || (c == '\r'))
  1397.     {
  1398.       *p = 0;
  1399.       return (s);
  1400.     }
  1401.       else if (c == '\b')
  1402.     {
  1403.       if (p != s)
  1404.         {
  1405.           p--;
  1406.           backup ();
  1407.           putccon (' ');
  1408.           backup ();
  1409.         }
  1410.     }
  1411.       else
  1412.     {
  1413.       *p++ = c;
  1414.       putccon (c);
  1415.     }
  1416.     }
  1417. }
  1418.  
  1419. void servermode (void)
  1420. {
  1421.   long rexxbit;
  1422.   long returnbits;
  1423.   rexxbit = upRexxPort ("IRexxSpell", rcl, NULL, &disp);
  1424.  
  1425.   setbuf (stdin, NULL);
  1426.   setbuf (stdout, NULL);
  1427.  
  1428.   while (KeepGoing)
  1429.     {
  1430.       returnbits = Wait (rexxbit | SIGBREAKF_CTRL_C);
  1431.       if (returnbits & SIGBREAKF_CTRL_C)
  1432.     KeepGoing = 0;
  1433.       if (returnbits & rexxbit)
  1434.     dispRexxPort ();
  1435.     }
  1436. /*
  1437.  *   With Rexx, we need to bring the port down.  You might make this
  1438.  *   part of exit() for programs that have multiple paths to exit.
  1439.  */
  1440.   dnRexxPort ();
  1441. }
  1442.  
  1443.  
  1444. /*
  1445.  *   Now we get into the actual code necessary for our REXX port; functions
  1446.  *   that do the real work.  Note that this program was not structured
  1447.  *   particularly nicely for Rexx; I had to write each of these functions.
  1448.  *   Many programs have these subroutines already in place; they are called
  1449.  *   as part of the event loop.  This progam, however, just has one big
  1450.  *   switch statement with different actions . . .
  1451.  *
  1452.  *   First, our locals.
  1453.  */
  1454. /*
  1455.  *   This is our main dispatch function.
  1456.  */
  1457. void disp (struct RexxMsg *msg, struct rexxCommandList *dat, char *p)
  1458. {
  1459.   (*(dat->userdata)) (msg, p);
  1460. }
  1461.  
  1462. /*
  1463.  *   This handler adds a word to the `global personal dictionary.'
  1464.  *
  1465.  *   Now, in English, the word is added to whatever personal
  1466.  *   dictionary was found when ISpell was started up in ARexx
  1467.  *   server mode. (Under a multiuser system, we might want to
  1468.  *   restrict who can add words to this dictionary.  For now
  1469.  *   we just do it!  Yes, the AmigaOS is multiuser, hehe :-).
  1470.  *   No protection, the way true hackers like it, you (the 
  1471.  *   user) get more rope to hang yourself :-), err the system 
  1472.  *   with :-).
  1473.  */
  1474. void rexxadd (struct RexxMsg *msg, char *p)
  1475. {
  1476.   if (*p)
  1477.     treeinsert (p, 1);
  1478.   treeoutput ();
  1479.   replyRexxCmd (msg, 0L, 0L, "ok");
  1480. }
  1481.  
  1482. /*
  1483.  *   The quick version does not write the changes to disk.
  1484.  *   Useful if you will be adding many words.  Be sure to
  1485.  *   call rexxadd at the end of the list (pass a null word,
  1486.  *   or a valid new word to be added).
  1487.  */
  1488. void rexxquickadd (struct RexxMsg *msg, char *p)
  1489. {
  1490.   if (*p)
  1491.     treeinsert (p, 1);
  1492.   replyRexxCmd (msg, 0L, 0L, "ok");
  1493. }
  1494.  
  1495. /*
  1496.  *   This handler checks the spelling of a word.
  1497.  */
  1498. void rexxcheck (struct RexxMsg *msg, char *p)
  1499. {
  1500.   char buf[512];
  1501.   register int i;
  1502.  
  1503.   if (good (p))
  1504.     {
  1505.       if (rootword[0] == 0)
  1506.     strcpy (buf, "*");
  1507.       else
  1508.     sprintf (buf, "+ %s", rootword);
  1509.     }
  1510.   else
  1511.     {
  1512.       makepossibilities (p);
  1513.       if (possibilities[0][0])
  1514.     {
  1515.       int bufend = 1;
  1516.       int possibilitysize;
  1517.  
  1518.       strcpy (buf, "&");
  1519.       for (i = 0; i < MAXPOSSIBLE; i++)
  1520.         {
  1521.           if (possibilities[i][0] == 0)
  1522.         break;
  1523.           possibilitysize = strlen(possibilities[i]);
  1524.           if ((possibilitysize + bufend) > 511)
  1525.         break;
  1526.           strcpy (&(buf[bufend++]), " ");
  1527.           strcpy (&(buf[bufend]), possibilities[i]);
  1528.           bufend += possibilitysize;
  1529.         }
  1530.     }
  1531.       else
  1532.     strcpy (buf, "#");
  1533.     }
  1534.   replyRexxCmd (msg, 0L, 0L, buf);
  1535. }
  1536.  
  1537. /*
  1538.  *   This handler checks the spelling of a word, it does
  1539.  *   not try to find replacement words as above.  It only
  1540.  *   determines whether or not the word is in the dictoinary.
  1541.  */
  1542. void rexxquickcheck (struct RexxMsg *msg, char *p)
  1543. {
  1544.   if (good (p))
  1545.     replyRexxCmd (msg, 0L, 0L, "ok");
  1546.   else
  1547.     replyRexxCmd (msg, 0L, 0L, "bad");
  1548. }
  1549.  
  1550. void rexxlookup (struct RexxMsg *msg, char *p)
  1551. {
  1552.   char buf[512];
  1553.   char cmd[512];
  1554.   char *rval;
  1555.   int whence = 0;
  1556.   int bufend = 1;
  1557.   int lookupsize;
  1558.  
  1559.   strcpy (buf, "&");
  1560.   sprintf (cmd, "^%s$", p);
  1561.   while ((rval = do_regex_lookup (cmd, whence++)) != NULL)
  1562.     {
  1563.       lookupsize = strlen(rval);
  1564.       if ((lookupsize + bufend) > 511)
  1565.     break;
  1566.       strcpy (&(buf[bufend++]), " ");
  1567.       strcpy (&(buf[bufend]), rval);
  1568.       bufend += lookupsize;
  1569.     }
  1570.   replyRexxCmd (msg, 0L, 0L, buf);
  1571. }
  1572.  
  1573. /*
  1574.  *   This handler checks the spelling of a file.
  1575.  */
  1576. void rexxfilecheck (struct RexxMsg *msg, char *p)
  1577. {
  1578.   char *cp;
  1579.  
  1580.   currentfile = p;
  1581.  
  1582.   if ((infile = fopen (p, "r")) == NULL)
  1583.     {
  1584.       replyRexxCmd (msg, 0L, 0L, "Error: Can't open input file");
  1585.       return;
  1586.     }
  1587.  
  1588.   tmpnam (tempfile);
  1589.  
  1590.   if ((outfile = fopen (tempfile, "w")) == NULL)
  1591.     {
  1592.       replyRexxCmd (msg, 0L, 0L, "Error: Can't open output file");
  1593.       return;
  1594.     }
  1595.  
  1596.   quit = 0;
  1597.  
  1598.   /* See if the file is a .tex file.  If so, set the appropriate flag. */
  1599.   if ((cp = strrchr (p, '.')) != NULL && strcmp (cp, ".tex") == 0)
  1600.     tflag = 1;
  1601.   else
  1602.     tflag = 0;
  1603.  
  1604.   lflag = 1;
  1605.  
  1606.   checkfile ();
  1607.  
  1608.   fclose (infile);
  1609.   fclose (outfile);
  1610.  
  1611.   replyRexxCmd (msg, 0L, 0L, tempfile);
  1612. }
  1613.  
  1614. /*
  1615.  *   This handler checks the spelling of a file using extended method.
  1616.  */
  1617. void rexxextendedfilecheck (struct RexxMsg *msg, char *p)
  1618. {
  1619.   char *cp;
  1620.  
  1621.   wflag = 1;
  1622.   RexxMsg = msg;
  1623.  
  1624.   currentfile = p;
  1625.  
  1626.   if ((infile = fopen (p, "r")) == NULL)
  1627.     {
  1628.       replyRexxCmd (msg, 0L, 0L, "Error: Can't open input file");
  1629.       return;
  1630.     }
  1631.  
  1632.   quit = 0;
  1633.  
  1634.   /* See if the file is a .tex file.  If so, set the appropriate flag. */
  1635.   if ((cp = strrchr (p, '.')) != NULL && strcmp (cp, ".tex") == 0)
  1636.     tflag = 1;
  1637.   else
  1638.     tflag = 0;
  1639.  
  1640.   lflag = 1;
  1641.  
  1642.   checkfile ();
  1643.  
  1644.   fclose (infile);
  1645.  
  1646.   replyRexxCmd (msg, 0L, 0L, "ok");
  1647.  
  1648.   wflag = 0;
  1649. }
  1650.  
  1651. /*
  1652.  *   This handler returns the version of the program.
  1653.  */
  1654. void rexxversion (struct RexxMsg *msg, char *p)
  1655. {
  1656.   char buf[512];
  1657.   int bufend = strlen(Version_ID);
  1658.   int namesize;
  1659.   int i;
  1660.  
  1661.   strcpy(buf, Version_ID);
  1662.   buf[bufend++] = '\n';
  1663.   for (i = 0; rcl[i].name != NULL; i++)
  1664.     {
  1665.       namesize = strlen(rcl[i].name);
  1666.       if ((namesize + bufend) > 511)
  1667.     break;
  1668.       strcpy (&(buf[bufend++]), " ");
  1669.       strcpy (&(buf[bufend]), rcl[i].name);
  1670.       bufend += namesize;
  1671.     }
  1672.   replyRexxCmd (msg, 0L, 0L, buf);
  1673. }
  1674.  
  1675. /*
  1676.  *   This handler sets the exit flag.
  1677.  */
  1678. void rexxexit (struct RexxMsg *msg, char *p)
  1679. {
  1680.   KeepGoing = 0;
  1681.   replyRexxCmd (msg, 0L, 0L, "bye");
  1682. }
  1683.  
  1684. void askmode (void)
  1685. {
  1686.   char buf[BUFSIZ];
  1687.   register int i;
  1688.  
  1689.   if (fflag)
  1690.     {
  1691.       if (freopen (askfilename, "w", stdout) == NULL)
  1692.     {
  1693.       fprintf (stderr, "Can't create %s\n", askfilename);
  1694.       exit (1);
  1695.     }
  1696.     }
  1697.  
  1698.   setbuf (stdin, NULL);
  1699.   setbuf (stdout, NULL);
  1700.  
  1701.   while (xgets (buf) != NULL)
  1702.     {
  1703.       /* *line is like `i', @line is like `a' */
  1704.       if (buf[0] == '*' || buf[0] == '@')
  1705.     {
  1706.       treeinsert (buf + 1, buf[0] == '*');
  1707.       fprintf (stdout, "*\n");
  1708.       treeoutput ();
  1709.     }
  1710.       else if (good (buf))
  1711.     {
  1712.       if (rootword[0] == 0)
  1713.         {
  1714.           fprintf (stdout, "*\n");    /* perfect match */
  1715.         }
  1716.       else
  1717.         {
  1718.           fprintf (stdout, "+ %s\n", rootword);
  1719.         }
  1720.     }
  1721.       else
  1722.     {
  1723.       makepossibilities (buf);
  1724.       if (possibilities[0][0])
  1725.         {
  1726.           fprintf (stdout, "& ");
  1727.           for (i = 0; i < MAXPOSSIBLE; i++)
  1728.         {
  1729.           if (possibilities[i][0] == 0)
  1730.             break;
  1731.           fprintf (stdout, "%s ", possibilities[i]);
  1732.         }
  1733.           fprintf (stdout, "\n");
  1734.         }
  1735.       else
  1736.         {
  1737.           fprintf (stdout, "#\n");
  1738.         }
  1739.     }
  1740.       if (sflag)
  1741.     {
  1742.       stop ();
  1743.       if (fflag)
  1744.         {
  1745.           rewind (stdout);
  1746.           creat (askfilename, 0666);
  1747.         }
  1748.     }
  1749.     }
  1750. }
  1751.  
  1752. /* Copy/ignore "cnt" number of characters pointed to by *cc. */
  1753. void copyout (char **cc, int cnt)
  1754. {
  1755.   while (--cnt >= 0)
  1756.     {
  1757.       if (*(*cc) == 0)
  1758.     break;
  1759.       if (!lflag)
  1760.     putc (*(*cc), outfile);
  1761.       (*cc)++;
  1762.     }
  1763. }
  1764.  
  1765. void lookharder (char *string)
  1766. {
  1767.   char cmd[150], grepstr[100];
  1768.   register char *g, *s;
  1769.  
  1770.   g = grepstr;
  1771.   for (s = string; *s != '\0'; s++)
  1772.     if (*s == '*')
  1773.       {
  1774.     *g++ = '.';
  1775.     *g++ = '*';
  1776.       }
  1777.     else
  1778.       *g++ = *s;
  1779.   *g = '\0';
  1780.   if (grepstr[0])
  1781.     regex_dict_lookup (cmd, grepstr);
  1782. }
  1783.  
  1784. void regex_dict_lookup (char *cmd, char *grepstr)
  1785. {
  1786.   char *do_regex_lookup ();
  1787.   char *rval;
  1788.   int whence = 0;
  1789.   int quit = 0;
  1790.   int count = 0;
  1791.   sprintf (cmd, "^%s$", grepstr);
  1792.   while (!quit && (rval = do_regex_lookup (cmd, whence++)) != NULL)
  1793.     {
  1794.       int ch;
  1795.       printcon ("%s\n", rval);;
  1796.       if ((count++ % (li - 1)) == 0)
  1797.     {
  1798.       inverse ();
  1799.       printcon ("-- more --");
  1800.       normal ();
  1801.       if ((ch = getccon ()) == 'q' || ch == 'Q' || ch == 'x' || ch == 'X')
  1802.         quit = 1;
  1803.       printcon ("\r                             \r");
  1804.     }
  1805.     }
  1806.   if (rval == NULL)
  1807.     {
  1808.       inverse ();
  1809.       printcon ("--eow--");
  1810.       normal ();
  1811.       getccon ();
  1812.     }
  1813. }
  1814.